﻿using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
using Verse.Sound;

namespace SZ.Mech
{

    public class Verb_MeleeCleave : Verb_MeleeAttack
    {
        protected override DamageWorker.DamageResult ApplyMeleeDamageToTarget(LocalTargetInfo target)
        {
            DamageWorker.DamageResult result = new DamageWorker.DamageResult();
            foreach (DamageInfo item in DamageInfosToApply(target))
            {
                if (!target.ThingDestroyed)
                {
                    result = target.Thing.TakeDamage(item);
                    TargetSputtering(target, item);
                    continue;
                }
            }


            //DamageInfo damageInfo = new DamageInfo(this.verbProps.meleeDamageDef, tool.power, this.verbProps.meleeArmorPenetrationBase, instigator: this.caster);
            //造成的总损失
            //damageResult.totalDamageDealt = Mathf.Min((float)target.Thing.HitPoints, damageInfo.Amount);

            //bool flag = GridsUtility.GetFirstPawn(target.Cell, target.Thing.Map) != null;
            //if (flag)
            //{
            //    //this.DrawCleaving(GridsUtility.GetFirstPawn(target.Cell, target.Thing.Map), base.CasterPawn);
              
            //}
            //target.Thing.TakeDamage(damageInfo);
            //return damageResult;
            return result;
        }
        private IEnumerable<DamageInfo> DamageInfosToApply(LocalTargetInfo target)
        {
            float num = verbProps.AdjustedMeleeDamageAmount(this, CasterPawn);
            float armorPenetration = verbProps.AdjustedArmorPenetration(this, CasterPawn);
            DamageDef def = verbProps.meleeDamageDef;
            BodyPartGroupDef bodyPartGroupDef = null;
            HediffDef hediffDef = null;
            num = Rand.Range(num * 0.8f, num * 1.2f);
            if (CasterIsPawn)
            {
                bodyPartGroupDef = verbProps.AdjustedLinkedBodyPartsGroup(tool);
                if (num >= 1f)
                {
                    if (base.HediffCompSource != null)
                    {
                        hediffDef = base.HediffCompSource.Def;
                    }
                }
                else
                {
                    num = 1f;
                    def = DamageDefOf.Blunt;
                }
            }
            ThingDef source = ((base.EquipmentSource == null) ? CasterPawn.def : base.EquipmentSource.def);
            Vector3 direction = (target.Thing.Position - CasterPawn.Position).ToVector3();
            bool instigatorGuilty = !(caster is Pawn pawn) || !pawn.Drafted;
            DamageInfo damageInfo = new DamageInfo(def, num, armorPenetration, -1f, caster, null, source, DamageInfo.SourceCategory.ThingOrUnknown, null, instigatorGuilty);
            damageInfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside);
            damageInfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
            damageInfo.SetWeaponHediff(hediffDef);
            damageInfo.SetAngle(direction);
            yield return damageInfo;
            if (tool != null && tool.extraMeleeDamages != null)
            {
                foreach (ExtraDamage extraMeleeDamage in tool.extraMeleeDamages)
                {
                    if (Rand.Chance(extraMeleeDamage.chance))
                    {
                        num = extraMeleeDamage.amount;
                        num = Rand.Range(num * 0.8f, num * 1.2f);
                        damageInfo = new DamageInfo(extraMeleeDamage.def, num, extraMeleeDamage.AdjustedArmorPenetration(this, CasterPawn), -1f, caster, null, source);
                        damageInfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside);
                        damageInfo.SetWeaponBodyPartGroup(bodyPartGroupDef);
                        damageInfo.SetWeaponHediff(hediffDef);
                        damageInfo.SetAngle(direction);
                        yield return damageInfo;
                    }
                }
            }
            if (!surpriseAttack || ((verbProps.surpriseAttack == null || verbProps.surpriseAttack.extraMeleeDamages.NullOrEmpty()) && (tool == null || tool.surpriseAttack == null || tool.surpriseAttack.extraMeleeDamages.NullOrEmpty())))
            {
                yield break;
            }
            IEnumerable<ExtraDamage> enumerable = Enumerable.Empty<ExtraDamage>();
            if (verbProps.surpriseAttack != null && verbProps.surpriseAttack.extraMeleeDamages != null)
            {
                enumerable = enumerable.Concat(verbProps.surpriseAttack.extraMeleeDamages);
            }
            if (tool != null && tool.surpriseAttack != null && !tool.surpriseAttack.extraMeleeDamages.NullOrEmpty())
            {
                enumerable = enumerable.Concat(tool.surpriseAttack.extraMeleeDamages);
            }
            foreach (ExtraDamage item in enumerable)
            {
                int num2 = GenMath.RoundRandom(item.AdjustedDamageAmount(this, CasterPawn));
                float armorPenetration2 = item.AdjustedArmorPenetration(this, CasterPawn);
                DamageInfo damageInfo2 = new DamageInfo(item.def, num2, armorPenetration2, -1f, caster, null, source);
                damageInfo2.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside);
                damageInfo2.SetWeaponBodyPartGroup(bodyPartGroupDef);
                damageInfo2.SetWeaponHediff(hediffDef);
                damageInfo2.SetAngle(direction);
                yield return damageInfo2;
            }
        }



        virtual protected void TargetSputtering(LocalTargetInfo target, DamageInfo damageInfo)
        {
            for (int i = 0; i < 4; i++)
            {
                IntVec3 c = target.Cell + GenAdj.CardinalDirectionsAround[i];
                Pawn pawn = Verb_MeleeCleave.GetFirstPawnNotDeadOrDowned(c, target.Thing.Map);
                if (pawn != null && pawn.Faction != this.caster.Faction)
                {
                    pawn.TakeDamage(damageInfo);
                    DrawCleaving(pawn, base.CasterPawn);
                }
            }
        }


        public static Pawn GetFirstPawnNotDeadOrDowned(IntVec3 c, Map map)
        {
            try
            {
                List<Thing> thingList = GridsUtility.GetThingList(c, map);
                for (int i = 0; i < thingList.Count; i++)
                {
                    Pawn pawn = thingList[i] as Pawn;
                    bool flag = pawn != null && !pawn.Dead && !pawn.Downed;
                    if (flag)
                    {
                        return pawn;
                    }
                }
            }
            catch(Exception e)
            {

            }
            return null;
        }
        protected void DrawCleaving(Pawn cleavedPawn, Pawn caster)
        {
            if (!caster.Dead && !caster.Downed)
            {
                bool flag2 = GenView.ShouldSpawnMotesAt(caster.Position, caster.Map, true) && !caster.Map.moteCounter.Saturated;
                if (flag2)
                {
                    float num = (float)(caster.Position.x - cleavedPawn.Position.x);
                    float x = (float)(caster.Position.z - cleavedPawn.Position.z);
                    bool flag3 = Mathf.Sqrt(Mathf.Pow(num, 2f) + Mathf.Pow(num, 2f)) > 1f;
                    if (flag3)
                    {
                        float num2 = Mathf.Atan2(num, x) * 180f / 3.1415927f;
                        Vector3 b = cleavedPawn.Position.ToVector3();

                        Mote moteThrown = (Mote)ThingMaker.MakeThing(ThingDefOf.Mote_Stun);
                        moteThrown.Attach(cleavedPawn);
                        //moteThrown.Scale = 1f;
                        //moteThrown.exactRotation = num2 + 180f;
                        //moteThrown.exactPosition = caster.DrawPos;
                        //moteThrown.SetVelocity(num2, -4f);
                        //moteThrown.airTimeLeft = GenGeo.MagnitudeHorizontal(moteThrown.exactPosition - b) / 4f;
                        GenSpawn.Spawn(moteThrown, caster.Position, caster.Map, 0);
                        //SoundStarter.PlayOneShot(Kijin3Defof.KijinCleaveSound, new TargetInfo(caster.Position, caster.Map, false));
                    }
                }
            }
        }

    }
}
